/**
 * Created by fanyongsheng on 2017/7/10.
 */

var PeerConnection = (window.PeerConnection || window.webkitPeerConnection00 || window.webkitRTCPeerConnection || window.mozRTCPeerConnection || '');
var URL = (window.URL || window.webkitURL || window.msURL || window.oURL || '');
var getUserMedia = (navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia || '');
var nativeRTCIceCandidate = (window.mozRTCIceCandidate || window.RTCIceCandidate || '');
var nativeRTCSessionDescription = (window.mozRTCSessionDescription || window.RTCSessionDescription || ''); // order is very important: "RTCSessionDescription" defined in Nighly but useless
var moz = !!navigator.mozGetUserMedia;
var iceServer = {
    "iceServers": [{
        "url": "stun:stun.l.google.com:19302"
    }]
};
var packetSize = 1000;
/**********************************************************/
/*                                                        */
/*                       网络事件处理器                       */
/*                                                        */
/**********************************************************/
function EventEmitter() {
    this.events = {};
}
//绑定事件函数
EventEmitter.prototype.on = function(eventName, callback) {
    this.events[eventName] = this.events[eventName] || [];
    this.events[eventName].push(callback);
};
//触发事件函数
EventEmitter.prototype.emit = function(eventName, _) {
    var events = this.events[eventName],
        args = Array.prototype.slice.call(arguments, 1),
        i, m;


    if (!events) {
        return;
    }
    for (i = 0, m = events.length; i < m; i++) {
        events[i].apply(null, args);
    }
};



/**********************************************************/
/*                                                        */
/*                   流及信道建立部分                     */
/*                                                        */
/**********************************************************/

/*******************基础部分*********************/
function webrtc() {
    //本地media stream
    this.localMediaStream = null;
    //所在房间
    this.roomid = "";
    //接收文件时用于暂存接收文件
    this.userid = -1;
    //本地WebSocket连接
    this.socket = null;
    //本地socket的id，由后台服务器创建
    this.sessionid = null;
    //socket is open
    this.is_socket = false;
    //保存所有与本地相连的peer connection， 键为socket id，值为PeerConnection类型
    this.peerConnections = {};
    //保存所有与本地连接的socket的id
    this.connections = [];
    //初始时需要构建链接的数目
    this.numStreams = 0;
    //初始时已经连接的数目
    this.initializedStreams = 0;
    //浏览器
    this.browserName = '';
    //是不是正常关闭
    this.normalCloseWebsocket = false;
    //房间用户列表
    this.userlist = [];
}


//继承自事件处理器，提供绑定事件和触发事件的功能
webrtc.prototype = new EventEmitter();



//本地连接信道，信道为websocket
webrtc.prototype.connect = function(addrs) {
    var socket,
        that = this;
    // 创建WebSocket
    if(this.socket) return false;
    if ('WebSocket' in window) {
        socket = this.socket =new WebSocket('ws:'+addrs[0],'anychat-protocol');
    } else if ('MozWebSocket' in window) {
        socket = this.socket =new MozWebSocket('ws:'+addrs[0],'anychat-protocol');
    } else {
        alert('WebSocket is not supported by this browser.');
        return;
    }
    socket.onopen = function() {
        that.is_socket = true;
        var json ={};
        if(that.sessionid){
            json = {
                "eventname": "request",
                "ssrc":0,
                "data": {
                    "cmdcode":"tokenconnect",
                    "sessionid":that.sessionid
                }
            }
        }else{
            json = {
                "eventname": "request",
                "ssrc":0,
                "data": {
                    "cmdcode":"connect"
                }
            }
        }
        socket.send(JSON.stringify(json));
    };

    socket.onmessage = function(message) {
        var json = JSON.parse(message.data);
        var data = json.data;
        if(typeof data !== 'object'){
            json.data = JSON.parse(data);
        }
        if (json.eventname) {
            that.emit(json.eventname, json);
        } else {
            that.emit("socket_receive_message", socket, json);
        }
    };

    socket.onerror = function(error) {
        console.log('socket_error');
        that.emit("socket_error", error, socket);
    };

    socket.onclose = function(data) {
        that.is_socket = false;
        if(!that.normalCloseWebsocket){
            that.emit("close_websocket",data);
        }
        that.normalCloseWebsocket = false;
        log('网络关闭');
        //console.log('close_websocket_1');
    };

    that.on('ready', function() {
        //that.createPeerConnections();
        //that.addStreams();
        //that.addDataChannels();
        //that.sendOffers();
    });
};


/**
 * 向网关服务器发送请求
 * @param eventnamem
 * @param ssrc
 * @param cmdcode
 * @param data
 */
webrtc.prototype.socket_send = function(eventnamem,ssrc,cmdcode,data){
    var send_json = {};
    send_json.eventname = eventnamem;
    send_json.ssrc = ssrc;
    send_json.data = {};
    send_json.data = data;
    send_json.data.cmdcode = cmdcode;
    if(this.is_socket){
        this.socket.send(
            JSON.stringify(send_json)
        );
    }

};

//判断是否支持webrtc
webrtc.prototype.support = function(){
    if(PeerConnection && getUserMedia && nativeRTCIceCandidate && nativeRTCSessionDescription){
        return true;
    }else{
        return false;
    }
};


/*************************流处理部分*******************************/


    //创建本地流
webrtc.prototype.createStream = function(videoid,deviceObj) {
    //log(this.connections);
    var that = this;
    var options = {},width,height,fpsctrl;
    if(deviceObj){
        width = deviceObj.width || 320;
        height = deviceObj.height || 240;
        fpsctrl = deviceObj.fpsctrl || 15;
    }else{
        width = 320;
        height =240;
        fpsctrl = 15
    }

    console.log('摄像头打开信息，分辨率w:'+width+'；分辨率h：'+height);

    options.video = {
        height:{ min: 0, ideal: height, max: 1920 },
        width:{ min: 0, ideal: width, max: 1080 },
        frameRate:{min:1, ideal: fpsctrl, max: 60 }
    };
    if(videoid){
        options.video.optional = [
            {
                'sourceId': videoid //0为前置摄像头，1为后置
            }
        ]
    }
    options.audio = true;
    if (getUserMedia) {
        //this.numStreams++;
        try {
            getUserMedia.call(navigator, options, function(stream) {
                    that.localMediaStream = stream;
                    that.initializedStreams++;
                    log('自己视频流打开成功');
                    that.emit("stream_created", stream);
                    that.emit("ready");
                    if (that.initializedStreams === that.numStreams) {

                    }
                },
                function(error) {
                    console.dir('视频流打开失败:'+error);

                    //that.emit("stream_create_error", error);
                });
        } catch (e) {
            options.video = true;
            getUserMedia.call(navigator, options, function(stream) {
                    that.localMediaStream = stream;
                    that.initializedStreams++;
                    log('catch自己视频流打开成功');
                    that.emit("stream_created", stream);
                    that.emit("ready");
                    if (that.initializedStreams === that.numStreams) {

                    }
                },
                function(error) {
                    console.dir('视频流打开失败:'+error);

                    //that.emit("stream_create_error", error);
                });
        }



    } else {
        that.emit("stream_create_error", new Error('WebRTC is not yet supported in this browser.'));
    }
};


//将本地流添加到所有的PeerConnection实例中
webrtc.prototype.addStreams = function(socketId) {
    var that = this;
    //clearInterval(int);
    var int = setInterval(function(){
        if(that.localMediaStream){
            clearInterval(int);
            that.peerConnections[socketId].addStream(that.localMediaStream);
            that.sendOffers(socketId);
        }
    },100);
};



//将流绑定到video标签上用于输出
webrtc.prototype.attachStream = function(stream, domId) {
    var element = document.getElementById(domId);
    if(element.className === 'my'){
        //自己的音量调成0
        element.volume = 0;
    }

    if ( element.mozSrcObject) {
        element.mozSrcObject = stream;
        element.play();
    }else if(element.srcObject){
        element.srcObject = stream;
        element.play();
    } else {
        element.src = URL.createObjectURL(stream);
    }
    element.src = URL.createObjectURL(stream);
};


/***********************信令交换部分*******************************/


    //向所有PeerConnection发送Offer类型信令
webrtc.prototype.sendOffers = function(socketId) {

    var i, m,
        pc,
        that = this,
        Jsonbuf = {};
        pcCreateOfferCbGen = function(pc, socketId) {
            return function(session_desc) {
                pc.setLocalDescription(session_desc);
                Jsonbuf = session_desc;
                that.emit("offer",Jsonbuf,socketId);
            };
        };
        pcCreateOfferErrorCb = function(error) {
            console.log(error);
        };
    pc = this.peerConnections[socketId];
    pc.createOffer(pcCreateOfferCbGen(pc, socketId), pcCreateOfferErrorCb);
    //for (i = 0, m = this.connections.length; i < m; i++) {
    //
    //}
};

//接收到Offer类型信令后作为回应返回answer类型信令
webrtc.prototype.receiveOffer = function(socketId, sdp) {
    var pc = this.peerConnections[socketId];
    this.sendAnswer(socketId, sdp);
};

//发送answer类型信令
webrtc.prototype.sendAnswer = function(socketId, sdp) {
    var pc = this.peerConnections[socketId];
    var that = this;
    pc.setRemoteDescription(new nativeRTCSessionDescription(sdp));
    pc.createAnswer(function(session_desc) {
        pc.setLocalDescription(session_desc);
        that.socket.send(JSON.stringify({
            "eventName": "__answer",
            "data": {
                "socketId": socketId,
                "sdp": session_desc
            }
        }));
    }, function(error) {
        console.log(error);
    });
};

//接收到answer类型信令后将对方的session描述写入PeerConnection中
webrtc.prototype.receiveAnswer = function(socketId, sdp) {
    var pc = this.peerConnections[socketId];
    if(!pc) return false;
    var obj = {};
    obj.type = 'answer';
    obj.sdp = sdp;
    pc.setRemoteDescription(new nativeRTCSessionDescription(obj));
};


/***********************点对点连接部分*****************************/


    //创建与其他用户连接的PeerConnections
webrtc.prototype.createPeerConnections = function() {
    var i, m;
    for (i = 0, m = this.connections.length; i < m; i++) {
        this.createPeerConnection(this.connections[i]);
    }
};

//创建单个PeerConnection
webrtc.prototype.createPeerConnection = function(socketId) {
    var that = this;
    var pc = new PeerConnection(iceServer);
    //var
    this.peerConnections[socketId] = pc;
    var data = {};
    var jsonbuf = {
        sdpMid:'',
        sdpMLineIndex:'',
        candidate:''
    };
    pc.onicecandidate = function(evt) {
        if(typeof evt.candidate === "object"){
            jsonbuf.sdpMid = evt.candidate.sdpMid;
            jsonbuf.sdpMLineIndex = evt.candidate.sdpMLineIndex;
            jsonbuf.candidate = evt.candidate.candidate;
            jsonbuf.peerconnectionid = socketId;
            jsonbuf.type = 'candidate';
            if (evt.candidate){
                data.jsonbuf = jsonbuf;
                that.socket_send('request',0,'webrtcconsult',data);
            }
        }

    };

    pc.onopen = function() {
        //that.emit("pc_opened", socketId, pc);
    };

    pc.onaddstream = function(evt) {
        that.emit('pc_add_stream', evt.stream, socketId, pc);
    };

    pc.ondatachannel = function(evt) {
        that.addDataChannel(socketId, evt.channel);
        that.emit('pc_add_data_channel', evt.channel, socketId, pc);
    };
    return pc;
};

//关闭PeerConnection连接
webrtc.prototype.closePeerConnection = function(pc) {
    if (!pc) return;
    pc.close();
};


//关闭所有PeerConnection连接
webrtc.prototype.closeAllPeerConnection = function(){
    //this.localMediaStream.close();
    for (var connection in this.peerConnections) {
        this.peerConnections[connection].close();
        delete this.peerConnections[connection];
    }
    log('关闭peerConnection');
};

//关闭其他人的connection
webrtc.prototype.closeOtherPeerConnection = function(pid){
    //this.localMediaStream.close();
    if(this.peerConnections[pid]){
        this.peerConnections[pid].close();
        delete this.peerConnections[pid];
    }

    log('关闭他人peerConnection:'+pid);
};

//移除所有的标签
webrtc.prototype.removeVideo = function(){
    var list = document.querySelectorAll('video.my,video.other');
    for(var li in list){
        if(!isNaN(li)){
            removeElement(list[li]);
        }
    }
    log('移除video标签');
    function removeElement(_element){
        var _parentElement = _element.parentNode;
        if(_parentElement){
            _parentElement.removeChild(_element);
        }
    }
};

//移除自己的标签
webrtc.prototype.removeMyVideo = function(){
    var list = document.querySelectorAll('video.my');
    for(var li in list){
        removeElement(list[li]);
    }
    log('移除自己video标签');
    function removeElement(_element){
        var _parentElement = _element.parentNode;
        if(_parentElement){
            _parentElement.removeChild(_element);
        }
    }
};

//移除他人的video 标签
webrtc.prototype.removeOtherVideo = function(pid){
    var list = document.querySelectorAll('video.other');
    for(var li in list){
        if(!isNaN(li)){
            if(list[li].getAttribute('name')==pid){
                removeElement(list[li]);
            }
        }
    }
    log('移除他人video标签：'+pid);
    function removeElement(_element){
        var _parentElement = _element.parentNode;
        if(_parentElement){
            _parentElement.removeChild(_element);
        }
    }
};

//接收候选者
webrtc.prototype.candidate = function(data){
    var candidate = new nativeRTCIceCandidate(data);
    var pc = this.peerConnections[data.peerconnectionid];
    if(!pc)return false;
    pc.addIceCandidate(candidate);
};


exports.instance = webrtc;